/*--------------------------------------------------------------------------------------------------
Yatak Operation System Project Copyright 2012-2013
Author : Ilya Churaev
Started : 4 Jun 2012		Updated : 17 Mar 2013
File Name : task.h			Purpose : define some types for task
--------------------------------------------------------------------------------------------------*/
#ifndef _TASK_H
#define _TASK_H

#include <yatak/paging.h>
#include <sys/types.h>
#include <yatak/tty.h>
#include <fs.h>

#define START_USERS_PID			100

#define PRIO_IDLE			0
#define PRIO_LOW			1
#define PRIO_NORMAL			2
#define PRIO_HIGH			3
#define PRIO_DEAD			99

// Per process flags
#define PF_KSOFTIRQD			0x00000001		// I am ksoftirqd
#define PF_STARTING			0x00000002		// being created
#define PF_EXITING			0x00000004		// getting shut down
#define PF_EXITPIDONE			0x00000008		// pi exit done on shut down
#define PF_VCPU				0x00000010		// I'm a virtual CPU
#define PF_FORKNOEXEC			0x00000040		// forked but didn't exec
#define PF_MCE_PROCESS			0x00000080		// process policy on mce errors
#define PF_SUPERPRIV			0x00000100		// used super-user privileges
#define PF_DUMPCORE			0x00000200		// dumped core
#define PF_SIGNALED			0x00000400		// killed by a signal
#define PF_MEMALLOC			0x00000800		// Allocating memory
#define PF_FLUSHER			0x00001000		// responsible for disk writeback
#define PF_USED_MATH			0x00002000		// if unset the fpu must be initialized before use
#define PF_FREEZING			0x00004000		// freeze in progress. do not account to load
#define PF_NOFREEZE			0x00008000		// this thread should not be frozen
#define PF_FROZEN			0x00010000		// frozen for system suspend
#define PF_FSTRANS			0x00020000		// inside a filesystem transaction
#define PF_KSWAPD			0x00040000		// I am kswapd
#define PF_OOM_ORIGIN			0x00080000		// Allocating much memory to others
#define PF_LESS_THROTTLE		0x00100000		// Throttle me less: I clean memory
#define PF_KTHREAD			0x00200000		// I am a kernel thread
#define PF_RANDOMIZE			0x00400000		// randomize virtual address space
#define PF_SWAPWRITE			0x00800000		// Allowed to write to swap
#define PF_SPREAD_PAGE			0x01000000		// Spread page cache over cpuset
#define PF_SPREAD_SLAB			0x02000000		// Spread some slab caches over cpuset
#define PF_THREAD_BOUND			0x04000000		// Thread bound to specific cpu
#define PF_MCE_EARLY			0x08000000		// Early kill for mce process policy
#define PF_MEMPOLICY			0x10000000		// Non-default NUMA mempolicy
#define PF_MUTEX_TESTER			0x20000000		// Thread belongs to the rt mutex tester
#define PF_FREEZER_SKIP			0x40000000		// Freezer should not count it as freezeable
#define PF_FREEZER_NOSIG		0x80000000		// Freezer won't send signals to it

/*
 * Task state bitmask. 
 *
 * We have two separate sets of flags: task->state
 * is about runnability, while task->exit_state are
 * about the task exiting. Confusing, but this way
 * modifying one set can't modify the other one by
 * mistake.
 */
#define TASK_STOPPED			0x00000000
#define TASK_RUNNING			0x00000001
#define TASK_SLEEPING			0x00000010
#define TASK_INTERRUPTIBLE		0x00000100
#define TASK_UNINTERRUPTIBLE		0x00001000
//#define TASK_TRACED			0x00010000
#define TASK_READY			0x00010000
#define TASK_WAITING			0x00100000
/* in tsk->exit_state */
#define EXIT_ZOMBIE			0x11110000
#define EXIT_DEAD			0x00001111
/* in tsk->state again */
#define TASK_DEAD			0x01000000
#define TASK_WAKEKILL			0x10000000

/* Convenience macros for the sake of set_task_state */
#define TASK_KILLABLE			(TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)
//#define TASK_STOPPED			(TASK_WAKEKILL | TASK_STOPPED)
//#define TASK_TRACED			(TASK_WAKEKILL | TASK_TRACED)

/* Convenience macros for the sake of wake_up */
#define TASK_NORMAL			(TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)
#define TASK_ALL			(TASK_NORMAL | TASK_STOPPED | TASK_TRACED)

#define PROC_NAME			64

struct task;

// This structure defines a 'thread' - a thread
struct thread
{
	tid_t tid;					// thread id. if main thread tid = pid
	uint32 eip;					// Instruction pointer.
	/*volatile*/ state_t state;			// Status of thread
	int prio, static_prio;				// dynamic and static priority
	
	int argc;					// Number of arguments
	void * argv;					// Arguments
	
	uint32 waitingfor;				// task waits for xx task
	struct ipc_message *msgbuf;			// Messagebuffer for task
	struct tty * terminal;				// Struct terminal
	
	struct task * parent;				// Process
	struct thread * next;
};

typedef struct thread thread_t;

// This structure defines a 'task' - a process.
struct task
{
	pid_t pid;					// process id
	char name [PROC_NAME];				// process name
	
	uid_t uid;					// user id
	
	/*volatile*/ state_t state;			// Status of process
	
	uint32 esp, ebp;				// Stack and base pointers.
	page_directory_t *page_directory;		// Page directory.
	
	thread_t * threads;				// List threads
	thread_t * cur_thread;				// Current thread
	
	struct task * brother;				// Brother task
	struct task * parent;				// Parent task
	struct task * child;				// Child task
	struct task * next;				// Next task
	
	// On a future
	gid_t gid;					// group id
	intid_t rirq;					// registet irq
	fs_node_t *files;				// files, which open in the process
	unsigned int flags;				// Additional flags
};

typedef struct task task_t;

struct pid_list
{
	pid_t pid;
	struct pid_list * next;
};
typedef struct pid_list pid_list_t;

task_t * CreateTaskStruct (char * name, pid_t id, page_directory_t * directory, int prio);

// Initialises the tasking system.
void init_tasking();

// Called by the timer hook, this changes the running process.
void switch_task();
void schedule();
void key_switch_task();
void task_control(pid_t pid, state_t state);

// Forks the current process, spawning a new one with a different
// memory space.
int fork();

// Causes the current process' stack to be forcibly moved to a new location.
void move_stack(void *new_stack_start, uint32 size);

// Returns the pid of the current process.
int getpid();

int start_task(char * name, bool daemon, void (*func)(void*), int argc, void *argv);

task_t * GetTask (pid_t pid);
pid_t get_current_pid ();
thread_t * GetThread (tid_t tid);

int kill_task(int pid);

void exit();

void set_task_priority (int prio);

//Threads
int new_thread();
int start_thread(task_t *thread, int attr, void (*func)(void*), void *arg);
int kill_thread(task_t *thread);

#endif